{
 "cells": [
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### Perceptron"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 1,
   "metadata": {},
   "outputs": [],
   "source": [
    "# 导入相关库\n",
    "import pandas as pd\n",
    "import numpy as np\n",
    "from sklearn.datasets import load_iris\n",
    "import matplotlib.pyplot as plt"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 2,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "2    50\n",
       "1    50\n",
       "0    50\n",
       "Name: label, dtype: int64"
      ]
     },
     "execution_count": 2,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "iris = load_iris()\n",
    "df = pd.DataFrame(iris.data, columns=iris.feature_names)\n",
    "df['label'] = iris.target\n",
    "df.columns = ['sepal length', 'sepal width', 'petal length', 'petal width', 'label']\n",
    "df.label.value_counts()"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 3,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "image/png": "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\n",
      "text/plain": [
       "<Figure size 432x288 with 1 Axes>"
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    }
   ],
   "source": [
    "plt.scatter(df[:50]['sepal length'], df[:50]['sepal width'], c='red', label='0')\n",
    "plt.scatter(df[50:100]['sepal length'], df[50:100]['sepal width'], c='green', label='1')\n",
    "plt.xlabel('sepal length')\n",
    "plt.ylabel('sepal width')\n",
    "plt.legend();"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 4,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/html": [
       "<div>\n",
       "<style scoped>\n",
       "    .dataframe tbody tr th:only-of-type {\n",
       "        vertical-align: middle;\n",
       "    }\n",
       "\n",
       "    .dataframe tbody tr th {\n",
       "        vertical-align: top;\n",
       "    }\n",
       "\n",
       "    .dataframe thead th {\n",
       "        text-align: right;\n",
       "    }\n",
       "</style>\n",
       "<table border=\"1\" class=\"dataframe\">\n",
       "  <thead>\n",
       "    <tr style=\"text-align: right;\">\n",
       "      <th></th>\n",
       "      <th>sepal length</th>\n",
       "      <th>sepal width</th>\n",
       "      <th>petal length</th>\n",
       "      <th>petal width</th>\n",
       "      <th>label</th>\n",
       "    </tr>\n",
       "  </thead>\n",
       "  <tbody>\n",
       "    <tr>\n",
       "      <th>0</th>\n",
       "      <td>5.1</td>\n",
       "      <td>3.5</td>\n",
       "      <td>1.4</td>\n",
       "      <td>0.2</td>\n",
       "      <td>0</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>1</th>\n",
       "      <td>4.9</td>\n",
       "      <td>3.0</td>\n",
       "      <td>1.4</td>\n",
       "      <td>0.2</td>\n",
       "      <td>0</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>2</th>\n",
       "      <td>4.7</td>\n",
       "      <td>3.2</td>\n",
       "      <td>1.3</td>\n",
       "      <td>0.2</td>\n",
       "      <td>0</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>3</th>\n",
       "      <td>4.6</td>\n",
       "      <td>3.1</td>\n",
       "      <td>1.5</td>\n",
       "      <td>0.2</td>\n",
       "      <td>0</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>4</th>\n",
       "      <td>5.0</td>\n",
       "      <td>3.6</td>\n",
       "      <td>1.4</td>\n",
       "      <td>0.2</td>\n",
       "      <td>0</td>\n",
       "    </tr>\n",
       "  </tbody>\n",
       "</table>\n",
       "</div>"
      ],
      "text/plain": [
       "   sepal length  sepal width  petal length  petal width  label\n",
       "0           5.1          3.5           1.4          0.2      0\n",
       "1           4.9          3.0           1.4          0.2      0\n",
       "2           4.7          3.2           1.3          0.2      0\n",
       "3           4.6          3.1           1.5          0.2      0\n",
       "4           5.0          3.6           1.4          0.2      0"
      ]
     },
     "execution_count": 4,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "df.head()"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 5,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "(100, 2) (100,)\n"
     ]
    }
   ],
   "source": [
    "data = np.array(df.iloc[:100, [0, 1, -1]])\n",
    "X, y = data[:,:-1], data[:,-1]\n",
    "y = np.array([1 if i == 1 else -1 for i in y])\n",
    "print(X.shape, y.shape)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 6,
   "metadata": {},
   "outputs": [],
   "source": [
    "# 定义参数初始化函数\n",
    "def initialize_parameters(dim):\n",
    "    w = np.zeros(dim, dtype=np.float32)\n",
    "    b = 0.0\n",
    "    return w, b"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 7,
   "metadata": {},
   "outputs": [],
   "source": [
    "# 定义sign符号函数\n",
    "def sign(x, w, b):\n",
    "    return np.dot(x,w)+b"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 23,
   "metadata": {},
   "outputs": [],
   "source": [
    "# 定义感知机训练函数\n",
    "def train(X_train, y_train, learning_rate):\n",
    "    # 参数初始化\n",
    "    w, b = initialize_parameters(X_train.shape[1])\n",
    "    # 初始化误分类\n",
    "    is_wrong = False\n",
    "    while not is_wrong:\n",
    "        wrong_count = 0\n",
    "        for i in range(len(X_train)):\n",
    "            X = X_train[i]\n",
    "            y = y_train[i]\n",
    "            # 如果存在误分类点\n",
    "            # 更新参数\n",
    "            # 直到没有误分类点\n",
    "            if y * sign(X, w, b) <= 0:\n",
    "                w = w + learning_rate*np.dot(y, X)\n",
    "                b = b + learning_rate*y\n",
    "                wrong_count += 1\n",
    "        if wrong_count == 0:\n",
    "            is_wrong = True\n",
    "            print('There is no missclassification!')\n",
    "        \n",
    "        # 保存更新后的参数\n",
    "        params = {\n",
    "            'w': w,\n",
    "            'b': b\n",
    "        }\n",
    "    return params"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 24,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "There is no missclassification!\n"
     ]
    }
   ],
   "source": [
    "params = train(X, y, 0.01)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 25,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "{'b': -1.2400000000000009, 'w': array([ 0.79 , -1.007])}"
      ]
     },
     "execution_count": 25,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "params"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 26,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "<matplotlib.legend.Legend at 0x26ab75348d0>"
      ]
     },
     "execution_count": 26,
     "metadata": {},
     "output_type": "execute_result"
    },
    {
     "data": {
      "image/png": "iVBORw0KGgoAAAANSUhEUgAAAYUAAAEKCAYAAAD9xUlFAAAABHNCSVQICAgIfAhkiAAAAAlwSFlzAAALEgAACxIB0t1+/AAAADl0RVh0U29mdHdhcmUAbWF0cGxvdGxpYiB2ZXJzaW9uIDIuMi4yLCBodHRwOi8vbWF0cGxvdGxpYi5vcmcvhp/UCwAAIABJREFUeJzt3Xl8VOXVwPHfIUGQRVRAUUMSEGR3AcS1ogY3ENBXq1hqReubVqxLS6tVEAHF7a2KVsGitlWhLrXKKi6AIFQFwQXCvkMQZA9LWLKc9487iRCz3CT3ztw7c76fz3wyc+fOnfPMQJ7c+zznOaKqGGOMMQA1Yh2AMcaY4LBOwRhjTDHrFIwxxhSzTsEYY0wx6xSMMcYUs07BGGNMMesUjDHGFLNOwRhjTDHfOwURSRKRb0RkUinP9RORrSLybeR2u9/xGGOMKVtyFN7jHmAJcEwZz7+tqr9ze7BGjRppenq6F3EZY0zCmD9//jZVbVzRfr52CiKSAvQAhgN/8OKY6enpzJs3z4tDGWNMwhCRdW728/vy0QjgPqCwnH2uE5EFIvKuiDQtbQcRyRSReSIyb+vWrb4EaowxxsdOQUSuBrao6vxydpsIpKvq6cBU4LXSdlLV0araWVU7N25c4dmPMcaYKvLzTOECoJeIrAXeAi4VkTGH76Cq21X1YOThy0AnH+MxxhhTAd/GFFT1AeABABG5GPijqv7y8H1E5CRV3RR52AtnQLrS8vLyyM7O5sCBA9WI2H+1a9cmJSWFmjVrxjoUY4wpVTRmHx1BRIYB81R1AnC3iPQC8oEdQL+qHDM7O5v69euTnp6OiHgXrIdUle3bt5OdnU2zZs1iHY4xxpQqKslrqjpDVa+O3B8c6RBQ1QdUtZ2qnqGql6jq0qoc/8CBAzRs2DCwHQKAiNCwYcPAn82YgBg7FtLToUYN5+fYsbGOyCSIqJ8p+CXIHUKRMMRoAmDsWMjMhNxc5/G6dc5jgL59YxeXSQi2zIUxQTNw4I8dQpHcXGe7MT6zTsFDH374Ia1ataJFixY88cQTsQ7HhNX69ZXbboyHErNT8OF6bUFBAXfeeSdTpkxh8eLFvPnmmyxevLjaxzUJKDW1ctuN8VDidQpF12vXrQPVH6/XVrNjmDt3Li1atKB58+YcddRR9OnTh/Hjx3sUtEkow4dDnTpHbqtTx9lujM8Sr1Pw6Xrtxo0badr0x1U6UlJS2LhxY7WOaRJU374wejSkpYGI83P0aBtkNlERN7OPXPPpeq2q/mSbzTYyVda3r3UCJiYS70zBp+u1KSkpbNiwofhxdnY2J598crWOaYwx0ZZ4nYJP12vPPvtsVqxYwZo1azh06BBvvfUWvXr1qtYxjTEm2hKvU/Dpem1ycjIvvPACV1xxBW3atOGGG26gXbt2HgVtjDHRkXhjCuDb9dru3bvTvXt3z49rjDHRknhnCsYYY8pknYIxxgRcYaHyzlcbWLZ5j+/vZZ2CMcYE2NLNu7nhb19w338W8NZX/i91kphjCsYYE3D7DuYzYupy/v7ftRxTO5mnrj+d6zum+P6+dqZgjBes/oHxiKryYdYmuj0zk5dnreHnnVKYPuBibujclBo1/E+ItTMFY6rL6h8Yj2zYkcvg8Vl8umwrrZvU54VfnEWntOOjGoOdKXjktttu44QTTqB9+/axDsVEm9U/MNV0ML+AF6avoNszM5m7ZgeDerRh0l0XRr1DgATtFMYuHEv6iHRqDK1B+oh0xi6s/ql+v379+PDDDz2IzoSO1T8w1fD5qm1c9dws/vLxcjLanMDUAV25/WfNSU6Kza/nhLt8NHbhWDInZpKb5/xlty5nHZkTnVP9vh2qfqp/0UUXsXbtWi9CNGGTmupcMiptuzFl2LrnIMMnL2bct9+Tenwd/nHr2VzS6oRYh5V4ZwoDpw0s7hCK5OblMnCaneqbKrL6B6YSCgqVN75Yy6VPz+CDhZu5+9IWfPz7iwLRIUACnimszyn9lL6s7cZUqGgweeBA55JRaqrTIdggsylhYXYOA8ctZEF2Dhe0aMiw3u05tXG9WId1hITrFFIbpLIu56en+qkN7FTfVIPVPzDl2H0gj6c/WsYbX66jYb1aPNfnTHqdcXIga64k3OWj4RnDqVPzyFP9OjXrMDzDTvVDz3IFTMCoKuO/3UjG0zN548t13HxuGtMGdKX3macEskOABOwU+nboy+ieo0lrkIYgpDVIY3TP0dUaZAa46aabOO+881i2bBkpKSm8+uqrHkVsXPGp9rYxVbVq615++eoc7nnrW05qUJvxd17I0N7tOaZ2zViHVi4prYxkkHXu3FnnzZt3xLYlS5bQpk2bGEVUOWGKNVTS00ufAZSWBjYrzETRgbwCRn66kpdmrqZWzRrcd0UrfnFOGklRyEYuj4jMV9XOFe2XcGMKJk5ZroAJgE+XbeHh8YtYvyOXa886hQe6t+aE+rVjHValWKdg4oPlCpgY2pSzn2ETFzMlazPNG9flX7efw/ktGsU6rCqJm05BVQM7cFMkbJfqQmX48CPXHwLLFTC+yy8o5J+fr+XZT5aTX6j86YpW3P6zZtRKTop1aFUWF51C7dq12b59Ow0bNgxsx6CqbN++ndq1w3UqGRqWK2CibP66HQx8P4ulm/dwSavGDOvdnqbH16n4hQHn+0CziCQB84CNqnp1iedqAa8DnYDtwI2qura845U20JyXl0d2djYHDhzwMnTP1a5dm5SUFGrWDPbsA2NM2XbuO8STHy7lra82cFKD2jzcsx1XtDsxsH+QFgnSQPM9wBLgmFKe+zWwU1VbiEgf4Engxsq+Qc2aNWnWrFn1ojQmjMaOtbOjKCksVN79OpsnpiwlZ38emRc1556MltStFRcXXIr52hoRSQF6AMOBP5SyS29gSOT+u8ALIiJqF9+NqZjVcYiaZZv3MGjcQr5au5POacfx6LXtad2ktL9zw8/vLm4EcB9Qv4znTwE2AKhqvojkAA2BbT7HZUz4lVfHwToFT+w7mM/z01bw6uw11K+dzFPXnc71nVKiUgEtVnzrFETkamCLqs4XkYvL2q2UbT85SxCRTCATINWmGBrjsNwM36gqHy36gWETF/F9zgFu7NyUP1/VmuPqHhXr0Hzn55nCBUAvEekO1AaOEZExqvrLw/bJBpoC2SKSDDQAdpQ8kKqOBkaDM9DsY8zGhIflZvhiw45cHp6wiOlLt9C6SX2ev+ksOqdHvwJarPi29pGqPqCqKaqaDvQBppfoEAAmALdE7l8f2cd+6RvjhtVx8NSh/EJe/HQllz07ky9Xb2dg9zZMvOvChOoQIAZ5CiIyDJinqhOAV4E3RGQlzhlCn2jHY0xoWW6GZ75YtZ1B4xayaus+rmzXhME923LysUfHOqyYiIsF8Ywxpiq27jnIYx8s4f1vNtL0+KMZ1qs9l7QORgU0r7nNU0i4pbONca1/f0hOBhHnZ//+sY7IeKSgUHnjy3VkPD2DSQu+53eXtODje7vGbYdQGfGVdWGMV/r3h1GjfnxcUPDj45EjYxOT8UTWxhwGvr+Q77JzOK95Qx65pj0tTghWScxYsstHxpQmOdnpCEpKSoL8/OjHY6pt94E8nvl4Oa9/sZbj69ZiUI829D4zmCUx/RCkZS6MCZ/SOoTytpvAUlUmLtjEI5MWs23vQW4+N40Bl7eiwdG2BllprFMwpjRJSWWfKZjQWL11L4PHL2L2ym10OKUBr/yqM2c0PTbWYQWadQrGlCYz88gxhcO3m8A7oiRmcg2G9W5H3wCUxAwD6xSMKU3RYPLo0c4ZQ1KS0yHYIHPgzVi2hYcnLGLd9lx6n3kyA3u0CV1JzFiyTsGYsowcaZ1AiGzOOcCwSYv4YOFmmjeqy9jbz+GCkJbEjCXLUzDB162bkytQdOvWLdYR+W/sWEhPhxo1nJ9jx8Y6osDKLyjklVmryXh6BtOWbGHAZacx5d6fWYdQRXamYIKtWzeYNu3IbdOmOdunTo1NTH6zOgmuzV+3k0HjsliyaTcXt2rMsF7tSW0Y/pKYsWR5CibYyptDHrJ/u66lp5e++mlaGqxdG+1oAmlXrlMS8825G2hyTG0e7tmWK9s3SZicg6qwPAVjwsrqJJRJVXl3fjaPR0pi3n5hM+697DTqxVlJzFiyT9KYoLE6CaVa/sMeBr2fxdy1O+iYeiyPXtOBtifHZ0nMWLKBZhNsGRmV2x4PrE7CEXIP5fP4lCV0f24Wy7fs4Yn/6cC7vz3fOgSf2JmCCbapU3862JyREb+DzGB1Eg7z8aLNDJ24mI279vPzTin8+arWNKxXK9ZhxTUbaDbGBM6GHbkMnbiIqUu2cNqJ9Rh+bQfOTrAKaF6zegomfng9Z9/t8SxXIOoO5RcycoZTEvO/K7fzwFWtmXz3z6xDiCK7fGSCzes5+26PZ7kCUffFqu08ND6LlVv2ckW7Exncsx2nJGhJzFiyy0cm2Lyes+/2eJYrEDXb9h7ksclLeO+bjaQcdzRDe7Ujo82JsQ4r7liegokPXs/Zd3s8yxXwXWGh8q+563nqw6XszyvgzktO5XeXtOToo2x58liyTsEEm9dz9t0ez3IFfJW1MYeB47L4bsMuzm1+PI9e054WJ9SPdVgGG2g2Qef1nH23x7NcAV/sOZDHkAmL6PXCbDbuzOXZG8/gzf891zqEALEzBRNsXs/Zd3s8yxXwlKoyKVISc+veg/Q9J5U/Xd6aBnWsJGbQ2ECzMcZXa7btY/D4LGat2Eb7U47h0Ws6cKaVxIw6y1NIdGGYYx+GGE2VHcgr4NlPlnPFiM/4dv0uhvRsy/g7L7QOIeDs8lE8CsMc+zDEaKrss+VbGTw+i7Xbc+l1xskM6tGGE46xkphhYJeP4lEY5tiHIUZTaZtzDvDI5MVMXrCJ5o3qMqx3ey5saRXQgsDyFBJZGObYhyFG41p+QSGvf7GOZz5ZzqGCQv5w2Wn8pmtzaiVbzkHYWKcQj8Iwxz4MMRpXvl6/k0HvZ7F40266ntaYYb3bkdawbqzDMlVkA83xKAxz7MMQoynXrtxDPPDeQq4b9Tnb9x1kZN+O/PPWs61DCDk7U4hHYZhjH4YYTalUlf98vZHHP1jCrv153HZBM35vJTHjhm8DzSJSG/gMqIXT+byrqg+X2Kcf8H/AxsimF1T1lfKOawPNxsTO8h/2MGhcFnPXWEnMsAlCnsJB4FJVPQM4E7hSRM4tZb+3VfXMyK3cDsHEmf79ITkZRJyf/ftXb79Y5j3Eec5F7qF8npiylO7PzWLZ5j08biUx45Zv53vqnILsjTysGbmFa/6r8U///jBq1I+PCwp+fDxyZOX3i2XeQ5znXHyy+AeGTFjExl37ub5TCg9YScy45muegogkAfOBFsCLqnp/ief7AY8DW4HlwO9VdUN5x7TLR3EiOdn5BV9SUhLk51d+v1jmPcRpzkX2zlyGTFjM1CU/cNqJ9Xj0mg50aWYV0MLK7eWjCjsFEakFXAekc9iZhaoOq0QwxwLvA3epatZh2xsCe1X1oIj8FrhBVS8t5fWZQCZAampqp3Wl/Qc04SJS9nOH/5t0u1+NGkc+Pvz1hYWVj68yYvnePjiUX8irs9fw/LQVANzbrSW3XdiMmkk2WTHMvExeGw/k4PzFf7AqwajqLhGZAVwJZB22ffthu70MPFnG60cDo8E5U6hKDCZgkpLKPgOoyn6xzHuIo5yLOau3M2hcFiu27OXytifycC8riZlo3HT9Kap6o6o+papPF90qepGINI6cISAiRwPdgKUl9jnpsIe9gCWViN2EWdE194q2u90vlnkPcZBzsX3vQQa88x03jv6S/XkFvPKrzoz+VWfrEBKRqpZ7w/kLvUNF+5XyutOBb4AFOGcHgyPbhwG9IvcfBxYB3wGfAq0rOm6nTp3UxIk77lBNSlIF5+cdd1RvvzFjVNPSVEWcn2PG+BV5sN67GgoKCnXMl2v19CEfaYsHJ+uTU5Zo7sH8WIdlfADMUxe/u8scUxCRhTizhZKBlsBqnMtH4vQlerovvVQFbKDZGG8s+j6Hge9n8a2VxEwIXuQpXA30BK7CmT10eeRx0XYTZH7Mm3ebL+D18dy2xes2e93egNhzII+hExfR86+z2bAjl2du+LEk5tiFY0kfkU6NoTVIH5HO2IXxlW9hXKjoVAJ4w822aN3s8pELY8ao1qnjXG4putWpU71LGnfcceTxim5lXcrx6nhu2+J1m71ubwAUFhbqxO82apfhn2j6nyfpg+8t0F37DhU/P2bBGK0zvI4yhOJbneF1dMyCcFwKM+WjupePiojI16ra8bDHScBCVW3rY19VJrt85IIf8+bd5gt4fTy3bfG6zV63N8bWbtvH4AmL+Gz51jJLYqaPSGddzk8/w7QGaay9d22UIjV+qfaUVBF5AHgQOFpEdhdtBg4RmR5qAsqPWgWl/YIsb7tXx3PbFq/b7HV7Y+RAXgEvzVzFyBmrOCqpBkN6tuXm89JJqvHT/I/1OaV/VmVtN/GpzDEFVX1cVesD/6eqx0Ru9VW1oao+EMUYTWWVNT++OvPmS+YFVLTdq+O5bYvXbfa6vTEwa8VWrhzxGSOmruCKdk2YPqAr/S5oVmqHAJDaoPTPqqztJj6V2SmISEcR6Qj8u+j+4bcoxmgqy495827zBbw+ntu2eN1mr9sbRT/sPsDv/vU1N786FxHhjV934a83nVVhjeThGcOpU/PIz7BOzToMzwhPvoXxQFmDDTh5A58CXwB5wDycrOY8YLabAQs/bjbQ7JIf8+bd5gt4fTy3bfG6zV6312d5+QX699mrtd3gD7XlwA90xCfLdf+hyuUcjFkwRtOeTVMZIpr2bJoNMscRXA40u5l99BaHJa8B7YF/ujm4HzfrFOJIrH7Zx6Fv1u/U7s99pmn3T9KbX52ja7bujXVIlWYdkr/cdgpu1j5qraoLDzuzyBKRM707VzEJye1y03G+LHV15eTm8eRHS3lz7npOqF+LF3/Rke4dmiDlLSQYQGMXjiVzYia5ec73vC5nHZkTne+5bwf7nqPJzZTUN4F9wBicDOdfAvVU9Sb/w/spm5IaJ2I11TROqCrvfb2Rxz5Yws7cQ/Q7vxm/v6wl9WvXjHVoVWLTYf3n5SqptwJ3APdEHn8GjCp7d2NciNVU0ziwIlISc86aHZyVeiyv/7oL7U5uEOuwqsWmwwZHhZ2Cqh4Ano3cjPGG2+Wm42hZ6uraf6iA56ev4OXPVlO3VjKPXduBPmc3pUYZU0zDJLVBaqlnCjYdNvrKm5L6TuTnQhFZUPIWvRBNXIrVVNOQmrr4B7o9M5NRM1ZxzVmnMH1AV35xTmpcdAhg02GDpLwzhaLLRVdHIxCTYIoGiQcOdC4FpaY6v+hLDh673S9Obdy1nyETFvHJYqck5ju/OS8uS2IWDSYPnDaQ9TnrSW2QyvCM4TbIHANuBppvA2ap6orohFQ+G2g2iSCvwCmJ+dxU57/dPd1a8msriWmqwYuls4ukA38TkVUi8o6I3GVTUn3g9bLPbo8Xy+Wh/VjeOw7MXbODHs/P4okpS7mwZSM++cNF/LbrqdXqEOJpSex4aotbUW2zm2SGyNnE0cDdwHqgwO3rvL7FZfKa18s+uz1eLJeH9mN575DbtueADnjnW027f5Ke//g0/WTRZk+OG09LYsdTW9zyqs14uHT2IOACoB5Oec3ZOJeTNvnXVZUtLi8feT0X3+3xYrk8tOUfFCssVN6et4Enpixl38F8/vei5tx1aQvqHOVmxnjF4ikHIJ7a4pZXbfYyT+F/gHxgMjAT+FKdaarGK17PxXd7vFguD235B4BTEnPQuCy+Wb+Lc5o5JTFbnuhtScx4ygGIp7a4Fe02V3iRUp0COxnAXOAyYKGIzPYlmkTl9bLPbo8Xy+Wh/VjeO0T2Hsxn2MTF9PzrbNZvz+Xpn5/BW5nnet4hQHwtiR1PbXEr2m2usFMQkfY4S1vcAtwIZAPTfYkmUXk9F9/t8WK5PHSC5h+oKpMXbCLj6Rn84/M19OmSyvQBF3NdpxTf1iuKpxyAeGqLW1Fvc0WDDjiXje4Dzgdquhmo8PMWlwPNqt6vBOr2eLFcHjrBVj9du22v3vzqHE27f5JeNeIz/Xrdjqi9dzytQBpPbXHLizbj1UBz0MTlQLOJawfzC3hpxmpenLGSo5JqMODy07j53DSSLefARJGXeQomjPzIAXB7zG7dnLyHolu3btV/75CavWIbV46YxbNTl3N52xOZNqArt17QzDqEEOo/uT/Jw5KRoULysGT6T65+Tk8Qcy68mfNmgsWPGgRuj9mtG0ybduRrp01ztk+dWrX3DqEtuw/wyOQlTPzue9Ib1uH127pw0WmNYx2WqaL+k/szat6Pi0MXaEHx45E9RlbpmEGtIWGXj+KRHzkAbo9Z3mBpyP6tVUVBofLGF2t5+uPlHCwopP/Fp/LbrqdSu2YUZnQZ3yQPS6ZAfzpVO0mSyB9ctZyeaOdcVDtPQUQm4hTVKZWq9qpibMZvfuQAWF5Bhb7bsIuB4xaStXE3P2vZiGG929OsUd1Yh2U8UFqHUN52N4Kac1He5aO/RC0K4y0/ahBYXYMy5eTm8X8fL2XsnPU0rleLF35xFj06nBS6kpimbEmSVOaZQlUFtYZEmaNdqjqzvFs0gzSV5EcOgNtjZmSU/vqytoeYqvLe19lkPDODf81ZT7/z05k2oCtXn36ydQhxJrNT6bk7ZW13I7A5FxXNWQVaAu8Ci4HVRTc38139uMVtnoLX/MgBcHvMjIwjF7rLyKj+ewfMih92641/+1zT7p+kvV+YrQuzd8U6JOOzOybdoUlDk5QhaNLQJL1jUvVzeqKZc4GHC+LNBh7GKcfZE6dms6jqw/51VWWzgWYTS/sPFfDX6St4edZqjq6ZxP1Xteams+OnApqJX17mKRytqtNwOoJ1qjoEuNRFALVFZK6IfCcii0RkaCn71BKRt0VkpYjMEZF0F/GEi9u5/WGoLeC29kKctLnkHPIHPxzJZc/OZOSMVfQ842Sm//Fi+p6TVqkOwe1cd6/nrwf9eLHkti3x1OZyVXQqAfwXp/N4D/gdcC2wzMXrBKgXuV8TmAOcW2Kf/sBLkft9gLcrOm6oLh+5rRkQhtoCbmsvxEmbS1vDXh6upW0fH6hfrNpWpWPeMemOI45XdCt5GcLrmgFBP14suW1LPLQZDy8fnQ0sAY4FHgEaAE+p6pduOx4RqYNTh+EOVZ1z2PaPgCGq+oWIJAObgcZaTlChunzkdm5/GGoLuK29ECdtLmsOeeoxqaz7fSlxu+B2rrvX89eDfrxYctuWeGizZ/UUVPWryAFrAHer6p5KBJEEzAdaAC8e3iFEnAJsiLxPvojkAA2BbSWOkwlkAqSGaQqk27n9YcgBcFt7IU7aXNZc8Q27N1T5mG7nuns9fz3ox4slt22JpzZXxM3S2Z1FZCGwAKeWwnci0snNwVW1QFXPBFKALpFluI84fGkvK+U4o1W1s6p2btw4REsFuK0ZEIbaAm5rL4S8zdv3HuRP//6OGoWNSn2+OnPIy5rTXnK71+vnB/14seS2LfHU5oq4GWj+O9BfVdNVNR24E/hHZd5EVXcBM4ArSzyVDTQFiFw+agDsqMyxA83t3P4w1BZwW3shpG0uLFTemruejGdm8v43G7muxZ84OtnbOeRu57p7PX896MeLJbdtiac2V6iiQQfgv262lbJPY+DYyP2jgVnA1SX2uZMjB5rfqei4oRpoVnU/tz8MtQXc1l4IWZsXf5+j/zPyv5p2/yT9+Uuf67LNu53wfJhD7nauu9fvHfTjxZLbtoS9zXg40PwsUAd4E+fSzo3ATuA/kU7l6zJedzrwGpCEc0byjqoOE5FhkeAmiEht4A3gLJwzhD6qurq8eEI10GwCbe/BfJ79ZDn//HwtDY6uyYPd23Bdx1MsG9nEJS/zFM4ETsNJYBsCtMGpwvY05ayPpKoLVPUsVT1dVdur6rDI9sGqOiFy/4Cq/lxVW6hql4o6hLgW8Dn78URV+WDhJro9PZNXZ6/hhs5NmT6gK9f7WBKzSNDnxPsRX9BzJBIm/8AlWzo7CErWKgDn+vro0VWvf2BKtW77PgaPX8TM5Vtpc9IxDL+2PR1Tj4vKe5dcPx+c69Kje44+Yv18t/uFIT6v2xL04wWZ2zMFN5ePTgQeA05W1atEpC1wnqq+6k2olROXnULA5+zHg4P5Bfxt5mpe/HQlyTWEP1zeilvOi25JzKDPifcjvqDnSMRD/oFbnuUpAP/EmW00MPJ4OfA2EJNOIS4FfM5+2P135TYeGpfF6m376NHhJB66ui1NGtSOehxBnxPvR3xBz5FIpPwDt9z8mdRIVd8BCsFJMgOqXlnC/FRA5+yH3ZY9B7j7zW/o+8ocClR57bYuvNi3Y0w6BAj+nHg/4gt6jkQi5R+45aZT2CciDYkklYnIuUCOr1ElmoDN2Q+7gkLltc/XkvGXmXyYtZm7M1ry0b0X0TXGNZKDPifej/iCniORUPkHblU0ZxXoiLMoXk7k53LgdDfzXf24hS5Pwa2AzNkPu+827NSrn5+lafdP0l++8qWu3ro31iEdIehz4v2IL+g5EmHPP3ALr/IUoDjbuBXOshTLVDXPr06qInE50GyqLWd/Hn/5aBlj5qyjcb1aPHR1W64+3UpiGlPEszwFEfk5Tk2FRcA1wNsi0tGDGI2pNlXl/W+yyXh6BmPnrOOW89KZOqArPc8Id0lMt3UXYiXo8UHwcz2Cys3so4dU9d8iciFwBU7C2ijgHF8jM6YCK7fs5aFxWXyxejtnND2Wf97ahfanNIh1WNXWf3J/Rs0bVfy4QAuKH4/sMTJWYRULenzw0/yDdTnryJzorDEVzVyPaL2vl9zkKXyjqmeJyOPAQlX9V9G26IR4JLt8ZPYfKuCFT1cw+jOnJOZ9V7bmpi6pJMVJSUy3dRdiJejxQfBzPWLByzyFjSLyN6Ab8KSI1MLdrCVjPDd96Q8MHr+I7J37+Z+zTuGB7m1oXL9WrMPylNu6C7ES9Pgg+LkeQeamU7gBZ8nrv6jqLhE5CfiTv2EZc6Tvd+1n6MRFfLToB1qcUI83//dczju1YazD8kWSJJWRpO7UAAATpElEQVT5l3gQBD0+cPIMSq2cF4Vcj1i8r5cq/ItfVXNV9T1VXRF5vElVP/Y/NGMgr6CQ0Z+totszM5m5fCt/uqIVH9z9s7jtEMB93YVYCXp8EPxcjyBzc6ZgTEzMW7uDQeOyWLp5DxmtT2BIr3Y0Pb5OxS8MuaLB2tHzR1OgBSRJEpmdMgMziBv0+ODHQd2B0wayPmc9qQ1SGZ4x3PfB3li9r5dslVQTODv2HeKJKUt4Z142JzeozcO92nF52xNDPcXUmFjzsp6CMVFRWKi8/dV6Ln16Bu99vZHfdG3O1AFduaJdE1cdQhjmh3sdo9f5AmH4DI2/7PKRCYQlm3YzaFwW89ftpEv68TxyTXtaNanv+vVhmB/udYxe5wuE4TM0/rPLRyam9h3MZ8TU5fz9v05JzAeual2lCmhBnh9exOsYvc4XCMNnaKrOyzwFYzynqny0aDNDJy5mU84BburSlPuuaM1xdY+q0vHCMD/c6xi9zhcIw2do/Gedgom69dtzeXhCFp8uc0pivvCLjnRKq15JzDDMD/c6Rq/zBcLwGRr/2UCziZqD+QW8MH0Flz07k7lrdjCoRxsm/u6CancIEI754V7H6HW+QBg+Q+M/O1MwUfH5ym0MGp/F6q376N6hCYOvbudpBbQwzA/3Okav8wXC8Bka/9lAs/HVlj0HGD55CeO//Z7U4+swrHc7Lm51QqzDMibhWJ6CiamCQuX1L9aS8fRMpix0SmJ+/PuL4rZD8Hp+v9vjWV6B8ZpdPjKeW5C9i0HjsliQncMFLRrySO/2NG9cL9Zh+cbr+f1uj2d5BcYPdvnIeCZnfx5Pf7yMN75cR6NIScyeCVAS0+v5/W6PZ3kFpjIsT8FEjaoy4bvveWTSEnbsO8gt56Xzh8tP45jaNWMdWlR4Pb/f7fEsr8D4wToFUy2rtjolMT9ftZ0zUhrwj35n0yEl/CUxK8Pr+f1uj2d5BcYPNtBsquRAXgFPf7yMq0bMYuHGHB65pj3v9b8g4ToE8H5+v9vjWV6B8YOdKZhK+3TpFgZPyGLDjv1ce9YpPBiHJTErw+v5/W6PZ3kFxg++DTSLSFPgdaAJUAiMVtXnSuxzMTAeWBPZ9J6qDivvuDbQHDubcvYzbOJipmRt5tTGdXnkmvacf2qjWIdljHEhCHkK+cAAVW0DnAvcKSJtS9lvlqqeGbmV2yGY2MgrKOTlz1aT8fRMpi/dwp+uaMWUey6KWocQhrn4lldQffbZBINvl49UdROwKXJ/j4gsAU4BFvv1nsZ789ftYOD7TknMS1ufwNAol8QMw1x8yyuoPvtsgiMqeQoikg58BrRX1d2Hbb8Y+A+QDXwP/FFVF5V3LLt8FB079x3iiSlLeXveBk5qUJshMSqJGYa5+JZXUH322fgvMHkKIlIP5xf/vYd3CBFfA2mquldEugPjgJalHCMTyARITbXpdn4qLFTenZ/N41OWsOdAPr+5qDl3Z7Skbq3YzEkIw1x8yyuoPvtsgsPXKakiUhOnQxirqu+VfF5Vd6vq3sj9D4CaIvKTC9WqOlpVO6tq58aNG/sZckJbunk3N/ztC+77zwJanFCPyXf/jAe6t4lZhwBlz7kP0lx8tzGGoS2xYp9NcPjWKYhzneFVYImqPlPGPk0i+yEiXSLxbPcrJlO6fQfzeeyDJfR4fjartu7lqetP5+3M8ypVI9kvYZiLb3kF1WefTXD4+SfgBcDNwEIR+Tay7UEgFUBVXwKuB+4QkXxgP9BHw7YYU4g5JTF/YOjERWzKOUCfs5ty/5VVL4nphzDMxbe8guqzzyY4bEG8BLVhRy4PT1jE9KVbaN2kPsOvbU+ntONjHZYxxidByFMwAXQov5AXP11Jt2dmMmf1dgb1aMOkuy70tENIxPnm/Sf3J3lYMjJUSB6WTP/J/WMdkjFVYstcJJDPV23joXFZrNq6j6vaN2Fwz7ac1OBoT98jEeeb95/cn1HzRhU/LtCC4sdVLY1pTKzY5aMEsHXPQYZPXsy4SEnMob3bcYlPFdAScb558rBkCrTgJ9uTJIn8wfkxiMiYnwpMnoKJnYJC5V9z1vHUR8s4mFfI3Ze2oP8lLahdM8m390zE+ealdQjlbTcmyKxTiFMLs3MYNG4h30VKYg7r3Z5To1ASMxHX+E+SpDLPFIwJGxtojjO7D+Tx8Pgser84m+9zDvBcnzMZ8+tzotIhQGLON8/slFmp7cYEmZ0pxImikpiPTl7C9r0HufncNAZc0SrqJTETcb550WDy6PmjKdACkiSJzE6ZNshsQskGmuPA6q17eWh8Fv9duZ3TUxow/JoOCVkBzRhTNstTiFdjx0J6OtSoQWFaGpP//BeuHDGLBdk5PNK7He+HqCRmPOUzxFNbYsU+w2CwM4UwGTsWMjMhN7d4U25yLd79zUNc+fgATqhfO4bBVU7JfAZwxh5G9xwduktN8dSWWLHP0H9uzxSsUwiT9HRY99OZPaSlwdq10Y6mWuIpnyGe2hIr9hn6zy4fxZn8gkJ0fRlz/cvaHmDxlM8QT22JFfsMg8M6hRCYv24nV/91Nhvrl1ETOYSFh+Jp/fx4akus2GcYHNYpBNjOfYf4838WcN2oz8nZn8f2B4egdUrUR65TB4aHLwcgnvIZ4qktsWKfYXBYnkIAqSr/np/NE1OWkrM/j8yLmnNPRkvq1sqAlAYwcKBzySg11ekQ+oZvIC6e8hniqS2xYp9hcNhAc8As27yHQeMW8tXanXROO45Hr21P6ybHxDosY0zI2UBzyOQeyufxD5bQ4/lZrNyyl6euO513fnOedQgmqvzIFbD8g3Cxy0cxpqp8vPgHhk5YxPcBLYlpEoMftTASsb5G2NnloxjasCOXIRMWMS1SEvPRa9rTOd1KYprY8CNXwPIPgsPqKQTYofxCXp61mr9OX0ENEQb1aMMt56dTM8mu5pnY8SNXwPIPwsc6hSj7YtV2Hhqfxcote30riWlMVfhRCyMR62uEnf1pGiXb9h7kD29/y00vf8nB/AL+0e9sRv2yk3UIJjD8yBWw/IPwsTMFnxUUKm/OXc9THy5lf14Bd13agjt9LolpTFX4kStg+QfhYwPNPsramMPAcVl8t2EX55/akEeuiU5JTGOMKckGmmNo94E8nvl4Oa9/sZbj69biuT5n0uuMkxGRWIdmjDHlsk7BQ6rKxAWbeHTSYrYWlcS8vBUNjo5uSUxjjKkq6xQ8snrrXgaPX8TsldvocEoDXrmlM6enHBvrsIwxplKsU6imA3kFjJyxipdmrKJWcg2G9W5H33PSSKphl4qMMeFjnUI1zFy+lcHjs1i3PZfeZ57MwB5tQlUS0xhjSrJOoQo25xzgkUmLmbxwE80b1WXs7edwQYsyCuAYY0yIWKdQCfkFhbz2xTqe+XgZ+YXKgMtOI7Nrc2olW86BMSY++NYpiEhT4HWgCVAIjFbV50rsI8BzQHcgF+inql/7FVN1zF+3k0HjsliyaTcXt2rMsF7tSW1Yp+IXGmNMiPi5zEU+MEBV2wDnAneKSNsS+1wFtIzcMoFRPsZTJbtyD/HAe05JzJ37DjGqb0f+0e9s6xA8YOvsGxM8vp0pqOomYFPk/h4RWQKcAiw+bLfewOvqpFV/KSLHishJkdfGlKry7vxsHo+UxLz9wmbce9lp1KtlV9y8YOvsGxNMUfkNJyLpwFnAnBJPnQJsOOxxdmRbTDuF5T/sYdD7Wcxdu4OOqccy/NoOtDnJKqB5aeC0gcUdQpHcvFwGThtonYIxMeR7pyAi9YD/APeq6u6ST5fykp8sxiQimTiXl0hN9W/J3dxD+Tw3bQWvzlpDvdrJPHldB37eqSk1LOfAc7bOvjHB5GunICI1cTqEsar6Xim7ZANND3ucAnxfcidVHQ2MBmdBPB9C5eNFmxk6cTEbd+3nhs4p/PmqNhxvJTF9Y+vsGxNMvg00R2YWvQosUdVnythtAvArcZwL5ER7PGHDjlxuf+0rMt+YT71ayfz7t+fx1PVnWIfgM1tn35hg8vNM4QLgZmChiHwb2fYgkAqgqi8BH+BMR12JMyX1Vh/jOULJkpgPdm/NrRc0s5KYUWLr7BsTTAlZT+HwkphXtDuRh3u24+RjrQKaMSZ+WT2FUmzbe5DHJi/hvW82knLc0bx6S2cy2pwY67CMMSYwEqZT+HTpFu556xv25xVw5yWn8rtLWnL0UbY8hTHGHC5hOoVmjepyVupxPHR1G1qcUD/W4RhjTCAlTKeQ3qgur93WJdZhGGNMoNlUG2OMMcWsUzDGGFPMOgVjjDHFrFMwxhhTzDoFY4wxxaxTMMYYU8w6BWOMMcWsUzDGGFMsdAviichW4KcL8bvTCNjmYTixZG0JpnhpS7y0A6wtRdJUtXFFO4WuU6gOEZnnZpXAMLC2BFO8tCVe2gHWlsqyy0fGGGOKWadgjDGmWKJ1CqNjHYCHrC3BFC9tiZd2gLWlUhJqTMEYY0z5Eu1MwRhjTDnitlMQkSQR+UZEJpXyXC0ReVtEVorIHBFJj36E7lXQln4islVEvo3cbo9FjG6IyFoRWRiJ8yeFtsXxfOR7WSAiHWMRZ0VctONiEck57DsZHIs43RCRY0XkXRFZKiJLROS8Es+H4jsBV20JxfciIq0Oi/FbEdktIveW2Me37yWei+zcAywBjinluV8DO1W1hYj0AZ4EboxmcJVUXlsA3lbV30Uxnuq4RFXLmmd9FdAycjsHGBX5GUTltQNglqpeHbVoqu454ENVvV5EjgLqlHg+TN9JRW2BEHwvqroMOBOcPwiBjcD7JXbz7XuJyzMFEUkBegCvlLFLb+C1yP13gQwRkWjEVlku2hJPegOvq+NL4FgROSnWQcUrETkGuAh4FUBVD6nqrhK7heI7cdmWMMoAVqlqyYRd376XuOwUgBHAfUBhGc+fAmwAUNV8IAdoGJ3QKq2itgBcFzmFfFdEmkYprqpQ4GMRmS8imaU8X/y9RGRHtgVNRe0AOE9EvhORKSLSLprBVUJzYCvwj8jlyVdEpG6JfcLynbhpC4TjezlcH+DNUrb79r3EXacgIlcDW1R1fnm7lbItcNOwXLZlIpCuqqcDU/nxDCiILlDVjjinvneKyEUlng/F90LF7fgaZ0mBM4C/AuOiHaBLyUBHYJSqngXsA/5cYp+wfCdu2hKW7wWAyCWwXsC/S3u6lG2efC9x1ykAFwC9RGQt8BZwqYiMKbFPNtAUQESSgQbAjmgG6VKFbVHV7ap6MPLwZaBTdEN0T1W/j/zcgnONtEuJXYq/l4gU4PvoROdeRe1Q1d2qujdy/wOgpog0inqgFcsGslV1TuTxuzi/WEvuE/jvBBdtCdH3UuQq4GtV/aGU53z7XuKuU1DVB1Q1RVXTcU69pqvqL0vsNgG4JXL/+sg+gfvrx01bSlxH7IUzIB04IlJXROoX3QcuB7JK7DYB+FVkZsW5QI6qbopyqOVy0w4RaVI0RiUiXXD+n22PdqwVUdXNwAYRaRXZlAEsLrFb4L8TcNeWsHwvh7mJ0i8dgY/fSzzPPjqCiAwD5qnqBJzBqDdEZCXOGUKfmAZXSSXacreI9ALycdrSL5axleNE4P3I/8lk4F+q+qGI/BZAVV8CPgC6AyuBXODWGMVaHjftuB64Q0Tygf1AnyD+0RFxFzA2cqliNXBrCL+TIhW1JTTfi4jUAS4DfnPYtqh8L5bRbIwxpljcXT4yxhhTddYpGGOMKWadgjHGmGLWKRhjjClmnYIxxphi1ikYU0mR1TZLW7G21O0evN81ItL2sMczRCQuag6b4LFOwZjguwZoW+FexnjAOgUTdyJZx5MjC59liciNke2dRGRmZCG7j4qywSN/eY8Qkc8j+3eJbO8S2fZN5Ger8t63lBj+LiJfRV7fO7K9n4i8JyIfisgKEXnqsNf8WkSWR+J5WUReEJHzcTLV/0+ctfVPjez+cxGZG9n/Zx59dMYkTkazSShXAt+rag8AEWkgIjVxFkHrrapbIx3FcOC2yGvqqur5kcXt/g60B5YCF6lqvoh0Ax4DrnMZw0CcZUluE5FjgbkiMjXy3JnAWcBBYJmI/BUoAB7CWa9nDzAd+E5VPxeRCcAkVX030h6AZFXtIiLdgYeBblX5oIwpyToFE48WAn8RkSdxfpnOEpH2OL/oP4n8Uk0CDl8r5k0AVf1MRI6J/CKvD7wmIi1xVqCsWYkYLsdZzPCPkce1gdTI/WmqmgMgIouBNKARMFNVd0S2/xs4rZzjvxf5OR9Ir0RcxpTLOgUTd1R1uYh0wlkb5nER+RhnNdNFqnpeWS8r5fEjwKeqeq04JVtnVCIMAa6LVNH6caPIOThnCEUKcP4fVrbIU9Exil5vjCdsTMHEHRE5GchV1THAX3AuySwDGkukbq+I1JQji6wUjTtciLPiZA7OkuobI8/3q2QYHwF3HbYq51kV7D8X6Coix4mznPvhl6n24Jy1GOM7+wvDxKMOOAOzhUAecIeqHhKR64HnRaQBzr/9EcCiyGt2isjnOHWwi8YZnsK5fPQHnGv8lfFI5PgLIh3DWqDM2sCqulFEHgPm4KyLvxinIiA4tTReFpG7cVb6NMY3tkqqSXgiMgP4o6rOi3Ec9VR1b+RM4X3g76pasmC7Mb6yy0fGBMcQEfkWp2jPGgJeLtLEJztTMMYYU8zOFIwxxhSzTsEYY0wx6xSMMcYUs07BGGNMMesUjDHGFLNOwRhjTLH/Bx79HtcXO5AHAAAAAElFTkSuQmCC\n",
      "text/plain": [
       "<Figure size 432x288 with 1 Axes>"
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    }
   ],
   "source": [
    "x_points = np.linspace(4, 7, 10)\n",
    "y_hat = -(params['w'][0]*x_points + params['b'])/params['w'][1]\n",
    "plt.plot(x_points, y_hat)\n",
    "\n",
    "plt.plot(data[:50, 0], data[:50, 1], color='red', label='0')\n",
    "plt.plot(data[50:100, 0], data[50:100, 1], color='green', label='1')\n",
    "plt.xlabel('sepal length')\n",
    "plt.ylabel('sepal width')\n",
    "plt.legend()"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "class Perceptron:\n",
    "    def __init__(self):\n",
    "        pass\n",
    "    \n",
    "    def sign(self, x, w, b):\n",
    "        return np.dot(x, w) + b\n",
    "    \n",
    "    def train(self, X_train, y_train, learning_rate):\n",
    "        # 参数初始化\n",
    "        w, b = self.initilize_with_zeros(X_train.shape[1])\n",
    "        # 初始化误分类\n",
    "        is_wrong = False\n",
    "        while not is_wrong:\n",
    "            wrong_count = 0\n",
    "            for i in range(len(X_train)):\n",
    "                X = X_train[i]\n",
    "                y = y_train[i]\n",
    "                # 如果存在误分类点\n",
    "                # 更新参数\n",
    "                # 直到没有误分类点\n",
    "                if y * self.sign(X, w, b) <= 0:\n",
    "                    w = w + learning_rate*np.dot(y, X)\n",
    "                    b = b + learning_rate*y\n",
    "                    wrong_count += 1\n",
    "            if wrong_count == 0:\n",
    "                is_wrong = True\n",
    "                print('There is no missclassification!')\n",
    "\n",
    "            # 保存更新后的参数\n",
    "            params = {\n",
    "                'w': w,\n",
    "                'b': b\n",
    "            }\n",
    "        return params"
   ]
  }
 ],
 "metadata": {
  "kernelspec": {
   "display_name": "Python 3",
   "language": "python",
   "name": "python3"
  },
  "language_info": {
   "codemirror_mode": {
    "name": "ipython",
    "version": 3
   },
   "file_extension": ".py",
   "mimetype": "text/x-python",
   "name": "python",
   "nbconvert_exporter": "python",
   "pygments_lexer": "ipython3",
   "version": "3.7.3"
  },
  "toc": {
   "base_numbering": 1,
   "nav_menu": {},
   "number_sections": true,
   "sideBar": true,
   "skip_h1_title": false,
   "title_cell": "Table of Contents",
   "title_sidebar": "Contents",
   "toc_cell": false,
   "toc_position": {},
   "toc_section_display": true,
   "toc_window_display": false
  }
 },
 "nbformat": 4,
 "nbformat_minor": 2
}
